package cc.iotkit.common.utils;

import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * Created by caimingkai-pc on 2017/11/21.
 */
public class ObjectConverter {
    /***
     * POJO 转为Map对象
     * @param obj
     * @return
     */
    public static Map<String, Object> pojo2Map(Object obj) {
        if (obj == null) {
            return null;
        }
        Map<String, Object> map = new HashMap<String, Object>();
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor property : propertyDescriptors) {
                String key =humpToLine(property.getName());
                // 过滤class属性
                if (!key.equals("class")) {
                    // 得到property对应的getter方法
                    Method getter = property.getReadMethod();
                    Object value = getter.invoke(obj);

                    map.put(key, value);
                }

            }
        } catch (Exception e) {
        }
        return map;

    }

    /***
     * 将实体转换为保存列表对象
     * @param obj
     * @return
     */
    public static List<Map<String, Object>> pojo2List(Object obj) {
        List<Map<String,Object>> list=new ArrayList<Map<String,Object>>();
        Map<String,Object> map=pojo2Map(obj);
        list.add(map);
        return list;
    }
        /***
         * Map对象转为POJO
         * @param map
         * @param beanClass
         * @return
         * @throws Exception
         */
    public static Object map2Pojo(Map<String, Object> map, Class<?> beanClass) throws IllegalAccessException, InstantiationException, IntrospectionException, InvocationTargetException, ParseException {
        if (map == null)
            return null;

        Object obj = beanClass.newInstance();

        BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
        for (PropertyDescriptor property : propertyDescriptors) {
            Method setter = property.getWriteMethod();
            String propertyName=ObjectConverter.humpToLine(property.getName());
            if (setter != null&& map.get(propertyName)!=null) {
                if(property.getPropertyType().getTypeName().equals("java.lang.Long")){
                    if(ObjectUtils.isEmpty(map.get(propertyName))) continue;
                    setter.invoke(obj,Long.parseLong(map.get(propertyName).toString()));
                }
                else if(property.getPropertyType().getTypeName().equals("java.lang.Integer")||property.getPropertyType().getTypeName().equals("int")){
                    if(ObjectUtils.isEmpty(map.get(propertyName))) continue;
                    setter.invoke(obj,Integer.parseInt(map.get(propertyName).toString()));
                }
                else if(property.getPropertyType().getTypeName().equals("java.util.Date")){
                    if(ObjectUtils.isEmpty(map.get(propertyName))) continue;
                    //待转换的时间字符串
                    String orginDate=map.get(propertyName).toString();
                    SimpleDateFormat sdf =null;
                    //如果时间长度大于10，使用时分秒格式
                    if(orginDate.length()>10)
                     sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    else
                        sdf = new SimpleDateFormat("yyyy-MM-dd");
                    Date date= sdf.parse(orginDate);
                    setter.invoke(obj,date );
                }
                else if(property.getPropertyType().getTypeName().equals("boolean")){
                    boolean value=map.get(propertyName).toString().equals("1")||map.get(propertyName).toString().toLowerCase().equals("true");
                    setter.invoke(obj, value);
                }
                /*else if(property.getPropertyType().getTypeName().equals("com.alibaba.fastjson.JSONArray")){
                    setter.invoke(obj, JSON.parseArray(map.get(propertyName).toString()));
                }*/
                else if(property.getPropertyType().getTypeName().equals("java.util.Collection")){
                    setter.invoke(obj, map.get(propertyName));
                }
                else
                    setter.invoke(obj, map.get(propertyName).toString());
            }
        }

        return obj;
    }

    public static Object map2Pojo(Map<String, Object> map, Class<?> beanClass,boolean bFormatConvert) throws Exception {
        if (map == null)
            return null;

        Object obj = beanClass.newInstance();

        BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
        for (PropertyDescriptor property : propertyDescriptors) {
            Method setter = property.getWriteMethod();
            String propertyName="";
            if(bFormatConvert)
                propertyName=ObjectConverter.humpToLine(property.getName());
            else
                propertyName=property.getName();
            if (setter != null&& map.get(propertyName)!=null) {
                if(property.getPropertyType().getTypeName().equals("java.lang.Long")){
                    if(ObjectUtils.isEmpty(map.get(propertyName))) continue;
                    setter.invoke(obj,Long.parseLong(map.get(propertyName).toString()));
                }
                else if(property.getPropertyType().getTypeName().equals("java.lang.Integer")||property.getPropertyType().getTypeName().equals("int")){
                    if(ObjectUtils.isEmpty(map.get(propertyName))) continue;
                    setter.invoke(obj,Integer.parseInt(map.get(propertyName).toString()));
                }
                else if(property.getPropertyType().getTypeName().equals("java.util.Date")){
                    if(ObjectUtils.isEmpty(map.get(propertyName))) continue;
                    //待转换的时间字符串
                    String orginDate=map.get(propertyName).toString();
                    SimpleDateFormat sdf =null;
                    //如果时间长度大于10，使用时分秒格式
                    if(orginDate.length()>10)
                        sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    else
                        sdf = new SimpleDateFormat("yyyy-MM-dd");
                    Date date= sdf.parse(orginDate);
                    setter.invoke(obj,date );
                }
                else if(property.getPropertyType().getTypeName().equals("boolean")){
                    setter.invoke(obj,Boolean.valueOf(map.get(propertyName).toString()) );
                }
                else
                    setter.invoke(obj, map.get(propertyName));
            }
        }

        return obj;
    }

    public static Object ListPojo2ListMap(List<?> list){
        if (list == null||list.size()==0)
            return null;

        Map<String,Object> obj = new HashMap<String,Object>();
        List listPojo=new ArrayList<>();
        for(Object map:list){
            obj=pojo2Map(map);
            listPojo.add(obj);
        }
        return listPojo;
    }

    public static Object listMap2ListPojo(List<Map<String, Object>> list, Class<?> beanClass) throws Exception {
        if (list == null||list.size()==0)
            return null;

        Object obj = beanClass.newInstance();
        List listPojo=new ArrayList<>();
        for(Map<String, Object> map:list){
            obj=map2Pojo(map,beanClass);
            listPojo.add(obj);
        }
        return listPojo;
    }

    /**
     * 下划线转驼峰
     * */
    public static String lineToHump(String str){
        Pattern linePattern = Pattern.compile("_(\\w)");
        str = str.toLowerCase();
        Matcher matcher = linePattern.matcher(str);
        StringBuffer sb = new StringBuffer();
        while(matcher.find()){
            matcher.appendReplacement(sb, matcher.group(1).toUpperCase());
        }
        matcher.appendTail(sb);
        return sb.toString();
    }
    /**
     *驼峰转下划线
     */
    public static String humpToLine(String str){
        Pattern humpPattern = Pattern.compile("[A-Z]");
        Matcher matcher = humpPattern.matcher(str);
        StringBuffer sb = new StringBuffer();
        while(matcher.find()){
            matcher.appendReplacement(sb, "_"+matcher.group(0).toLowerCase());
        }
        matcher.appendTail(sb);
        return sb.toString();
    }

    /***
     * 设置查询语句中的字段别名为驼峰命名方式
     * 例：seelect user_id from xxx 更改为select user_id as userId from xxx
     * @param sql
     * @return
     */
    public static String setSqlAlias(String sql){
        sql=sql.toLowerCase();
        int startIndex= sql.indexOf("select")+6;
        int endIndex= sql.indexOf("from");
        String selectFields=sql.substring(startIndex,endIndex);
        String[] splitFields= selectFields.split(",");
        selectFields="";
        for(String field:splitFields){
            String[] f= field.split("\\.");
            //如果已定义了别名不再进行别名设置
            if(field.indexOf(" as ")>0) {
                selectFields+=field+",";
                continue;
            }
            if(f.length>1){
                selectFields+=field+" as "+ ObjectConverter.lineToHump(f[1])+",";
            }
            else{
                selectFields+=field+" as "+ ObjectConverter.lineToHump(field)+",";
            }

        }
        selectFields=selectFields.substring(0,selectFields.length() - 1);
        sql="select "+selectFields+" "+sql.substring(endIndex);
        return sql;
    }

    /***
     * 字符串转时间类型
     * @param strDate   时间字符串，必须为2000-12-22格式或2018-12-12 20:23:22
     * @param isShortFormat 是否为短时间
     * @return
     */
    public static Date String2Date(String strDate,boolean isShortFormat){
        //注意：SimpleDateFormat构造函数的样式与strDate的样式必须相符
        SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat sDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //加上时间
        //必须捕获异常
        try {
            Date date=null;
            if(isShortFormat)
                date=simpleDateFormat.parse(strDate);
            else
                date=sDateFormat.parse(strDate);
            return date;
        } catch(ParseException px) {
            throw new RuntimeException(px.getMessage());
        }
    }

    /**
     * 根据某个字段对list进行分组
     * @param list  需要分组的list
     * @param fieldName 分组字段
     * @return
     */
    public static Map<String, List<Map<String,Object>>> getGroupsListToMap(List<Map<String,Object>> list,String fieldName){
        /*2、分组算法**/
        Map<String, List<Map<String,Object>>> groupMap = new HashMap<>();
        for (Map<String,Object> row : list) {
            String key=row.get(fieldName).toString();
            List<Map<String,Object>> tempList = groupMap.get(key);
            /*如果取不到数据,那么直接new一个空的ArrayList**/
            if (tempList == null) {
                tempList = new ArrayList<>();
                tempList.add(row);
                groupMap.put(key, tempList);
            }
            else {
                /*某个sku之前已经存放过了,则直接追加数据到原来的List里**/
                tempList.add(row);
            }
        }
        return groupMap;
    }

    /**
     * 根据某个字段对list进行分组
     * @param list  需要分组的list
     * @param fieldName 分组字段
     * @return
     */
    public static List<Map<String,Object>> getGroupsListToTree(List<Map<String,Object>> list,String fieldName){
         List<Map<String,Object>> treeNode=new ArrayList<>();
         String key="";
         List<Map<String,Object>> tempList=new ArrayList<>();
        for (Map<String,Object> row : list) {
            Map<String,Object> newRow=new HashMap<String,Object>();
            newRow.putAll(row);
            String rowKey=row.get(fieldName).toString();
            if (StringUtils.isEmpty(key)|| !key.equals(rowKey)) {
                tempList =new ArrayList<>();
                Map<String,Object> tempRow=new HashMap<>();
                tempRow.putAll(row);
                tempList.add(tempRow);
                newRow.put("children",tempList);
                treeNode.add(newRow);
            }
            else{
                tempList.add(newRow);
            }
            key=rowKey;
        }
/*        list.forEach((row)->{
            String rowKey=row.get(fieldName).toString();
            if (StringUtils.isEmpty(key)|| !key.equals(rowKey)) {
                tempList =new ArrayList<>();
                Map<String,Object> tempRow=new HashMap<>();
                tempRow.put("id",row.get("id"));
                tempRow.put("org_id",row.get("org_id"));
                tempRow.put("role_name",row.get("role_name"));
                tempRow.put("org_name",row.get("org_name"));
                tempList.add(tempRow);
                row.put("children",tempList);
                treeNode.add(row);
            }
            else{
                tempList.add(row);
            }
            key=rowKey;
        });*/


        return treeNode;
    }
}
